/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.mvc.views.rope
{
	import com.puny.mvc.models.Model;
	
	import flash.geom.Point;
	
	public class RopeParticle extends Model
	{
		public static const G:Point = new Point(0,9.8);
		public static const DT:Number = 0.02;
		private var _mg:Point;
		private var _dt2:Number = DT * DT;
		private var _particles:Array = new Array();
		private var _velocity:Point = new Point();
		private var _last:Number = 0;
		private var _tracks:Array = new Array();
		private var _g_length:Number = G.length;

		public function RopeParticle()
		{
			this["interstice"] = 50;
			this["mass"] = 400;
			this["ks"] = 2000;
			this["ka"] = 100;
			this["fixed"] = false;
			initialize(0,0);
		}
		
		public function initialize(x:Number,y:Number):void {
			this["position"] = new Point(x,y);
			_tracks = [new Point(x,y), new Point(x,y)];
			_mg = new Point(this["mass"] * G.x, this["mass"] * G.y);
		}

		public function connection(pt:RopeParticle):void {
			_particles.push(pt);
		}
		
		public function get current():Point {
			return _tracks[1];
		}

		public function update():void {
			if (this["fixed"]) {
				return ;
			}
			var f:Point = _mg;
			var pt:Point
			for each(var particle:RopeParticle in _particles) {
				pt = particle.current.subtract(this["position"]);
				f = f.add(getTension(pt));
			}
//			trace("f=",f.length);

			this["position"].x = verlet(_tracks[0].x,_tracks[1].x,f.x);
			this["position"].y = verlet(_tracks[0].y,_tracks[1].y,f.y);
			
//			adjustLength(particle);
			
//			trace(_tracks[0],_tracks[1], this["position"]);
			_velocity.x = this["position"].x - _tracks[1].x;
			_velocity.y = this["position"].y - _tracks[1].y;
		}
		
		private function adjustLength(particle:RopeParticle):void {
			var pt:Point = particle.current.subtract(this["position"]);
			var l:Number = pt.length;
			var dl:Number = pt.length - this["interstice"];
			if (dl > 0) {
				this["position"].x += dl * pt.x / l;
				this["position"].y += dl * pt.y / l;
			}
		}
		
		private function verlet(r0:Number,r1:Number,f:Number):Number {
			return 2 * r1 - r0 + f*_dt2;
		} 
		
		public function record():void {
			var pt:Point = _tracks.shift();
			pt.x = this["position"].x;
			pt.y = this["position"].y;
			_tracks.push(pt);
		}		

		private function getTension(pt:Point):Point {
			var l:Number = pt.length;
			var dl:Number = l - this["interstice"];
			var k:Number = this["ks"] * dl / l;
//			return new Point(0,0);

//			return new Point(k * pt.x - _k_for_air * _velocity.x , k * pt.y - _k_for_air * _velocity.y );

			return (dl > 0) ? new Point(k * pt.x - this["ka"] * _velocity.x , k * pt.y - this["ka"] * _velocity.y ) : new Point(0,0);
//			trace("dl=",dl);
//			l = _length;
//			var t:Number = _g_length * pt.y / l;
//			return (dl>0) ? new Point(- t * pt.x / l - _k_for_air * _velocity.x , -t * pt.y / l - _k_for_air * _velocity.y ) : new Point(0,0);
		}
	}
}